#include <linux/module.h>
#include <linux/init.h>
#include <linux/irqreturn.h>
#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>

/*
	mykeys{
		interrupt-parent = <&gpiof>;
		interrupts = <9 0>,<7 0>, <8 0>; 
        interrupts-name = "key1", "key2", "key3"
	};
 */

typedef struct
{
    unsigned int m_irqNumber;
    const char* m_irqName;
}btn_desc;

static btn_desc btns[3];
static struct device_node* btnNode;

irqreturn_t btn_irqHandler(int irqNumber, void* dev)
{
    btn_desc* data = (btn_desc*)dev;
    printk("%d: %s is pressed!\n",data->m_irqNumber, data->m_irqName);
    return IRQ_HANDLED;
}

static int __init btn_drv_init(void)
{
    int ret = 0, i = 0;
    btnNode = of_find_node_by_path("/mykeys");
    for(i = 0; i < ARRAY_SIZE(btns); i++)
    {
        btns[i].m_irqNumber = irq_of_parse_and_map(btnNode,i);
        of_property_read_string_index(btnNode, "interrupts-name", i, &btns[i].m_irqName);
        ret = request_irq(btns[i].m_irqNumber, btn_irqHandler, IRQF_TRIGGER_FALLING, btns[i].m_irqName, &btns[i]);
        if(ret < 0)
        {
            printk("irq \"%d\" request is failed", btns[i].m_irqNumber);
            return ret;
        }
    }
    return 0;
}

static void __exit btn_drv_exit(void)
{
    int i = 0;
    for(i = 0; i < ARRAY_SIZE(btns); i++)
    {
        free_irq(btns[i].m_irqNumber, &btns[i]);
    }
}

module_init(btn_drv_init);
module_exit(btn_drv_exit);

MODULE_LICENSE("GPL");